added samples
[windows-sources.git] / sdk / samples / all in on code / Visual Studio 2008 / CSUACSelfElevation / ReadMe.txt
blob57f6df491f77b046264995bda7424293d86ccd87
1 =============================================================================
2           APPLICATION : CSUACSelfElevation Project Overview
3 =============================================================================
5 /////////////////////////////////////////////////////////////////////////////
6 Summary: 
8 User Account Control (UAC) is a new security component in Windows Vista and 
9 newer operating systems. With UAC fully enabled, interactive administrators 
10 normally run with least user privileges. This example demonstrates how to 
11 check the privilege level of the current process, and how to self-elevate 
12 the process by giving explicit consent with the Consent UI. 
15 /////////////////////////////////////////////////////////////////////////////
16 Prerequisite:
18 You must run this sample on Windows Vista or newer operating systems.
21 /////////////////////////////////////////////////////////////////////////////
22 Demo:
24 The following steps walk through a demonstration of the UAC sample.
26 Step1. After you successfully build the sample project in Visual Studio 2008, 
27 you will get an application: CSUACSelfElevation.exe. 
29 Step2. Run the application as a protected administrator on a Windows Vista or 
30 Windows 7 system with UAC fully enabled. The application should display the 
31 following content on the main dialog.
33   IsUserInAdminGroup:     True
34   IsRunAsAdmin:           False
35   IsProcessElevated:      False
36   Integrity Level:        Medium
38 There is a UAC shield icon on the Self-elevate button.
40 Step3. Click on the Self-elevate button. You will see a Consent UI.
42   User Account Control
43   ---------------------------------- 
44   Do you want to allow the following program from an unknown publisher to 
45   make changes to this computer?
47 Step4. Click Yes to approve the elevation. The original application will then 
48 be started and display the following content on the main dialog.
50   IsUserInAdminGroup:     True
51   IsRunAsAdmin:           True
52   IsProcessElevated:      True
53   Integrity Level:        High
55 The Self-elevate button on the dialog does not have the UAC shield icon this 
56 time. That is, the application is running as elevated administrator. The 
57 elevation succeeds. If you click on the Self-elevate button again, the 
58 application will tell you that it is running as administrator.
60 Step5. Close the application. 
63 /////////////////////////////////////////////////////////////////////////////
64 Implementation:
66 Step1. Create a new Visual C# Windows Forms project named CSUACSelfElevation.
68 Step2. Add controls to the main form
70   Type: Button
71   ID: btnElevate
72   Caption: "Self-elevate"
73   
74   Type: Label
75   ID: lbInAdminGroup
76   Use: Display whether the primary access token of the process belongs to 
77   user account that is a member of the local Administrators group, even if it 
78   currently is not elevated.
79   
80   Type: Label
81   ID: lbIsRunAsAdmin
82   Use: Display whether the application is run as administrator. 
83   
84   Type: Label
85   ID: lbIsElevated
86   Use: Display whether the process is elevated or not. Token elevation is 
87   only available on Windows Vista and newer operating systems. The label 
88   shows N/A on systems prior to Windows Vista.
90   Type: Label
91   ID: lbIntegrityLevel
92   Use: Display the integrity level of the current process. Integrity level is 
93   only available on Windows Vista and newer operating systems. The label 
94   shows N/A on systems prior to Windows Vista.
96 Step3. Check and display the current process's "run as administrator" status, 
97 elevation information and integrity level when the application initializes 
98 the main dialog.
100 Create the following four helper functions:
102     /// <summary>
103     /// The function checks whether the primary access token of the process belongs 
104     /// to user account that is a member of the local Administrators group, even if 
105     /// it currently is not elevated.
106     /// </summary>
107     /// <returns>
108     /// Returns true if the primary access token of the process belongs to user 
109     /// account that is a member of the local Administrators group. Returns false 
110     /// if the token does not.
111     /// </returns>
112     /// <exception cref="System.ComponentModel.Win32Exception">
113     /// When any native Windows API call fails, the function throws a Win32Exception 
114     /// with the last error code.
115     /// </exception>
116     internal bool IsUserInAdminGroup()
118     /// <summary>
119     /// The function checks whether the current process is run as administrator.
120     /// In other words, it dictates whether the primary access token of the 
121     /// process belongs to user account that is a member of the local 
122     /// Administrators group and it is elevated.
123     /// </summary>
124     /// <returns>
125     /// Returns true if the primary access token of the process belongs to user 
126     /// account that is a member of the local Administrators group and it is 
127     /// elevated. Returns false if the token does not.
128     /// </returns>
129     internal bool IsRunAsAdmin()
130     
131     /// <summary>
132     /// The function gets the elevation information of the current process. It 
133     /// dictates whether the process is elevated or not. Token elevation is only 
134     /// available on Windows Vista and newer operating systems, thus 
135     /// IsProcessElevated throws a C++ exception if it is called on systems prior 
136     /// to Windows Vista. It is not appropriate to use this function to determine 
137     /// whether a process is run as administartor.
138     /// </summary>
139     /// <returns>
140     /// Returns true if the process is elevated. Returns false if it is not.
141     /// </returns>
142     /// <exception cref="System.ComponentModel.Win32Exception">
143     /// When any native Windows API call fails, the function throws a Win32Exception 
144     /// with the last error code.
145     /// </exception>
146     /// <remarks>
147     /// TOKEN_INFORMATION_CLASS provides TokenElevationType to check the elevation 
148     /// type (TokenElevationTypeDefault / TokenElevationTypeLimited / 
149     /// TokenElevationTypeFull) of the process. It is different from TokenElevation 
150     /// in that, when UAC is turned off, elevation type always returns 
151     /// TokenElevationTypeDefault even though the process is elevated (Integrity 
152     /// Level == High). In other words, it is not safe to say if the process is 
153     /// elevated based on elevation type. Instead, we should use TokenElevation. 
154     /// </remarks>
155     internal bool IsProcessElevated()
156     
157     /// <summary>
158     /// The function gets the integrity level of the current process. Integrity 
159     /// level is only available on Windows Vista and newer operating systems, thus 
160     /// GetProcessIntegrityLevel throws a C++ exception if it is called on systems 
161     /// prior to Windows Vista.
162     /// </summary>
163     /// <returns>
164     /// Returns the integrity level of the current process. It is usually one of 
165     /// these values:
166     /// 
167     ///    SECURITY_MANDATORY_UNTRUSTED_RID - means untrusted level. It is used 
168     ///    by processes started by the Anonymous group. Blocks most write access.
169     ///    (SID: S-1-16-0x0)
170     ///    
171     ///    SECURITY_MANDATORY_LOW_RID - means low integrity level. It is used by
172     ///    Protected Mode Internet Explorer. Blocks write acess to most objects 
173     ///    (such as files and registry keys) on the system. (SID: S-1-16-0x1000)
174     /// 
175     ///    SECURITY_MANDATORY_MEDIUM_RID - means medium integrity level. It is 
176     ///    used by normal applications being launched while UAC is enabled. 
177     ///    (SID: S-1-16-0x2000)
178     ///    
179     ///    SECURITY_MANDATORY_HIGH_RID - means high integrity level. It is used 
180     ///    by administrative applications launched through elevation when UAC is 
181     ///    enabled, or normal applications if UAC is disabled and the user is an 
182     ///    administrator. (SID: S-1-16-0x3000)
183     ///    
184     ///    SECURITY_MANDATORY_SYSTEM_RID - means system integrity level. It is 
185     ///    used by services and other system-level applications (such as Wininit, 
186     ///    Winlogon, Smss, etc.)  (SID: S-1-16-0x4000)
187     /// 
188     /// </returns>
189     /// <exception cref="System.ComponentModel.Win32Exception">
190     /// When any native Windows API call fails, the function throws a Win32Exception 
191     /// with the last error code.
192     /// </exception>
193     internal int GetProcessIntegrityLevel()
195 Some of the methods need to P/Invoke some native Windows APIs. The P/Invoke 
196 signatures are defined in NativeMethod.cs.
198 In the constructor of the main form, check and display the "run as 
199 administrator" status, the elevation information, and the integrity level of 
200 the current process.
202     // Get and display whether the primary access token of the process belongs 
203     // to user account that is a member of the local Administrators group even 
204     // if it currently is not elevated (IsUserInAdminGroup).
205     try
206     {
207         bool fInAdminGroup = IsUserInAdminGroup();
208         this.lbInAdminGroup.Text = fInAdminGroup.ToString();
209     }
210     catch (Exception ex)
211     {
212         this.lbInAdminGroup.Text = "N/A";
213         MessageBox.Show(ex.Message, "An error occurred in IsUserInAdminGroup",
214             MessageBoxButtons.OK, MessageBoxIcon.Error);
215     }
217     // Get and display whether the process is run as administrator or not 
218     // (IsRunAsAdmin).
219     try
220     {
221         bool fIsRunAsAdmin = IsRunAsAdmin();
222         this.lbIsRunAsAdmin.Text = fIsRunAsAdmin.ToString();
223     }
224     catch (Exception ex)
225     {
226         this.lbIsRunAsAdmin.Text = "N/A";
227         MessageBox.Show(ex.Message, "An error occurred in IsRunAsAdmin",
228             MessageBoxButtons.OK, MessageBoxIcon.Error);
229     }
232     // Get and display the process elevation information (IsProcessElevated) 
233     // and integrity level (GetProcessIntegrityLevel). The information is not 
234     // available on operating systems prior to Windows Vista.
235     if (Environment.OSVersion.Version.Major >= 6)
236     {
237         // Running Windows Vista or later (major version >= 6). 
239         try
240         {
241             // Get and display the process elevation information.
242             bool fIsElevated = IsProcessElevated();
243             this.lbIsElevated.Text = fIsElevated.ToString();
245             // Update the Self-elevate button to show the UAC shield icon on 
246             // the UI if the process is not elevated.
247             this.btnElevate.FlatStyle = FlatStyle.System;
248             NativeMethod.SendMessage(btnElevate.Handle, 
249                 NativeMethod.BCM_SETSHIELD, 0, 
250                 fIsElevated ? IntPtr.Zero : (IntPtr)1);
251         }
252         catch (Exception ex)
253         {
254             this.lbIsElevated.Text = "N/A";
255             MessageBox.Show(ex.Message, "An error occurred in IsProcessElevated",
256                 MessageBoxButtons.OK, MessageBoxIcon.Error);
257         }
259         try
260         {
261             // Get and display the process integrity level.
262             int IL = GetProcessIntegrityLevel();
263             switch (IL)
264             {
265             case NativeMethod.SECURITY_MANDATORY_UNTRUSTED_RID:
266                 this.lbIntegrityLevel.Text = "Untrusted"; break;
267             case NativeMethod.SECURITY_MANDATORY_LOW_RID:
268                 this.lbIntegrityLevel.Text = "Low"; break;
269             case NativeMethod.SECURITY_MANDATORY_MEDIUM_RID:
270                 this.lbIntegrityLevel.Text = "Medium"; break;
271             case NativeMethod.SECURITY_MANDATORY_HIGH_RID:
272                 this.lbIntegrityLevel.Text = "High"; break;
273             case NativeMethod.SECURITY_MANDATORY_SYSTEM_RID:
274                 this.lbIntegrityLevel.Text = "System"; break;
275             default:
276                 this.lbIntegrityLevel.Text = "Unknown"; break;
277             }
278         }
279         catch (Exception ex)
280         {
281             this.lbIntegrityLevel.Text = "N/A";
282             MessageBox.Show(ex.Message, "An error occurred in GetProcessIntegrityLevel",
283                 MessageBoxButtons.OK, MessageBoxIcon.Error);
284         }
285     }
286     else
287     {
288         this.lbIsElevated.Text = "N/A";
289         this.lbIntegrityLevel.Text = "N/A";
290     }
292 Step4. Handle the click event of the Self-elevate button. When user clicks 
293 the button, elevate the process by restarting itself with 
294 ProcessStartInfo.UseShellExecute = true and ProcessStartInfo.Verb = "runas" 
295 if the process is not run as administrator.
297     private void btnElevate_Click(object sender, EventArgs e)
298     {
299         // Elevate the process if it is not run as administrator.
300         if (!IsRunAsAdmin())
301         {
302             // Launch itself as administrator
303             ProcessStartInfo proc = new ProcessStartInfo();
304             proc.UseShellExecute = true;
305             proc.WorkingDirectory = Environment.CurrentDirectory;
306             proc.FileName = Application.ExecutablePath;
307             proc.Verb = "runas";
309             try
310             {
311                 Process.Start(proc);
312             }
313             catch
314             {
315                 // The user refused the elevation.
316                 // Do nothing and return directly ...
317                 return;
318             }
320             Application.Exit();  // Quit itself
321         }
322         else
323         {
324             MessageBox.Show("The process is running as administrator", "UAC");
325         }
326     }
328 Step5. Automatically elevate the process when it's started up.
330 If your application always requires administrative privileges, such as during 
331 an installation step, the operating system can automatically prompt the user 
332 for privileges elevation each time your application is invoked. 
334 If a specific kind of resource (RT_MANIFEST) is found embedded within the 
335 application executable, the system looks for the <trustInfo> section and 
336 parses its contents. Here is an example of this section in the manifest file:
338     <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
339        <security>
340           <requestedPrivileges>
341              <requestedExecutionLevel
342                 level="requireAdministrator"
343              />
344           </requestedPrivileges>
345        </security>
346     </trustInfo>
348 Three different values are possible for the level attribute
350   a) requireAdministrator 
351   The application must be started with Administrator privileges; it won't run 
352   otherwise.
354   b) highestAvailable 
355   The application is started with the highest possible privileges.
356   If the user is logged on with an Administrator account, an elevation prompt 
357   appears. If the user is a Standard User, the application is started 
358   (without any elevation prompt) with these standard privileges.
360   c) asInvoker 
361   The application is started with the same privileges as the calling 
362   application.
364 To configure the elevation level in this Visual C# Windows Forms project, 
365 open the project's properties, turn to the Security tab, check the checkbox 
366 "Enable ClickOnce Security Settings", check "This is a fulltrust application" 
367 and close the application Properies page. This creates an app.manifest file 
368 and configures the project to embed the manifest. You can open the 
369 "app.manifest" file from Solution Explorer by expanding the Properies folder. 
370 The file has the following content by default.
372     <?xml version="1.0" encoding="utf-8"?>
373     <asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" 
374     xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" 
375     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
376       <assemblyIdentity version="1.0.0.0" name="MyApplication.app" />
377       <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
378         <security>
379           <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
380             <!-- UAC Manifest Options
381                 If you want to change the Windows User Account Control level replace the 
382                 requestedExecutionLevel node with one of the following.
384             <requestedExecutionLevel  level="asInvoker" uiAccess="false" />
385             <requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />
386             <requestedExecutionLevel  level="highestAvailable" uiAccess="false" />
388                 If you want to utilize File and Registry Virtualization for backward 
389                 compatibility then delete the requestedExecutionLevel node.
390             -->
391             <requestedExecutionLevel level="asInvoker" uiAccess="false" />
392           </requestedPrivileges>
393           <applicationRequestMinimum>
394             <PermissionSet class="System.Security.PermissionSet" version="1" 
395             Unrestricted="true" ID="Custom" SameSite="site" />
396             <defaultAssemblyRequest permissionSetReference="Custom" />
397           </applicationRequestMinimum>
398         </security>
399       </trustInfo>
400     </asmv1:assembly>
402 Here we are focusing on the line:
404     <requestedExecutionLevel level="asInvoker" uiAccess="false" />
406 You can change it to be 
408     <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
410 to require the application always be started with Administrator privileges.
413 /////////////////////////////////////////////////////////////////////////////
414 References:
416 MSDN: User Account Control
417 http://msdn.microsoft.com/en-us/library/aa511445.aspx
419 MSDN: Windows Vista Application Development Requirements for User Account 
420 Control Compatibility
421 http://msdn.microsoft.com/en-us/library/bb530410.aspx
424 /////////////////////////////////////////////////////////////////////////////